{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d1e26707-6880-4f55-aabb-157f95c64230",
   "metadata": {},
   "outputs": [],
   "source": [
    "# File: fitting.ipynb\n",
    "# Code: Claude Code and Codex\n",
    "# Review: Ryoichi Ando (ryoichi.ando@zozo.com)\n",
    "# License: Apache v2.0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "49fa95ad-6a12-4d46-a102-3050e2bef2d4",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import random\n",
    "\n",
    "from frontend import App\n",
    "\n",
    "# create an app\n",
    "app = App.create(\"fitting\")\n",
    "\n",
    "# set up paths to Codim-IPC repository assets\n",
    "codim_ipc_root = \"/tmp/Codim-IPC\"\n",
    "checkout_list = [\n",
    "    \"Projects/FEMShell/input/dress_knife\",\n",
    "    \"Projects/FEMShell/input/Rumba_Dancing\",\n",
    "]\n",
    "\n",
    "# sparse clone only needed directories from the repository\n",
    "app.extra.sparse_clone(\n",
    "    \"https://github.com/ipc-sim/Codim-IPC\", codim_ipc_root, checkout_list\n",
    ")\n",
    "\n",
    "stage_path = os.path.join(codim_ipc_root, checkout_list[0], \"stage.obj\")\n",
    "body_path = os.path.join(codim_ipc_root, checkout_list[1], \"shell0.obj\")\n",
    "\n",
    "# load dress mesh with stitching information\n",
    "V, F, S = app.extra.load_CIPC_stitch_mesh(stage_path)\n",
    "app.asset.add.tri(\"dress\", V, F)\n",
    "app.asset.add.stitch(\"glue\", S)\n",
    "\n",
    "# load body mesh\n",
    "V, F = app.mesh.load_tri(body_path)\n",
    "app.asset.add.tri(\"body\", V, F)\n",
    "\n",
    "# create a scene\n",
    "scene = app.scene.create()\n",
    "\n",
    "# add dress with stitching and rotation\n",
    "dress = scene.add(\"dress\")\n",
    "dress.param.set(\"friction\", 0.0).set(\"strain-limit\", 0.1)\n",
    "dress.stitch(\"glue\").rotate(-90, \"x\")\n",
    "\n",
    "# add body with animated motion from sequence of meshes\n",
    "jitter = 0.01 * random.random()\n",
    "body = scene.add(\"body\").at(0, -0.78 + jitter, 0)\n",
    "body.param.set(\"friction\", 0.0).set(\"model\", \"arap\")\n",
    "pin = body.pin()\n",
    "\n",
    "# load body animation sequence from files\n",
    "body_dir = os.path.join(codim_ipc_root, checkout_list[1])\n",
    "frame = 1\n",
    "while True:\n",
    "    path = os.path.join(body_dir, f\"shell{frame}.obj\")\n",
    "    if os.path.exists(path):\n",
    "        V, _ = app.mesh.load_tri(path)\n",
    "        t0, t1 = 0.5 + 0.025 * (frame - 1), 0.5 + 0.025 * frame\n",
    "        pin.move_to(V, t0, t1)\n",
    "        frame += 1\n",
    "    else:\n",
    "        break\n",
    "\n",
    "# compile the scene and report stats\n",
    "scene = scene.build().report()\n",
    "\n",
    "# preview the initial scene\n",
    "scene.preview(options={\"pin\": False})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "220de44e-60d3-4958-939f-1b270fdaefdc",
   "metadata": {},
   "outputs": [],
   "source": [
    "# create a new session with the compiled scene\n",
    "session = app.session.create(scene)\n",
    "\n",
    "# set session parameters with dynamic fitting mode\n",
    "param = session.param.set(\"fitting\").set(\"dt\", 1e-3).set(\"frames\", 240)\n",
    "\n",
    "# configure dynamic parameters to transition out of fitting mode\n",
    "param.dyn(\"fitting\").time(0.15).hold().change(False)\n",
    "param.dyn(\"dt\").time(0.15).hold().change(0.01)\n",
    "\n",
    "# build this session\n",
    "session = session.build()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0d75bab9-537f-4e4b-8463-e9b70fe59b8c",
   "metadata": {},
   "outputs": [],
   "source": [
    "# start the simulation and live-preview the results\n",
    "session.start().preview()\n",
    "\n",
    "# also show simulation logs in realtime\n",
    "session.stream()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9a004ff6-739f-480c-b082-08fe8f0643c0",
   "metadata": {},
   "outputs": [],
   "source": [
    "# create an animation from the simulation results\n",
    "session.animate()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "11166aad-83b1-4bfd-8f1c-000aa745b7f7",
   "metadata": {},
   "outputs": [],
   "source": [
    "# export the animation to file\n",
    "session.export.animation()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8ded698a-c2fa-445b-8a0e-27dbc3e320ba",
   "metadata": {},
   "outputs": [],
   "source": [
    "# this is for CI\n",
    "if app.ci:\n",
    "    assert session.finished()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
